package com.openlogic.common.logic.run;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.text.StringEscapeUtils;
import org.noear.solon.annotation.Component;
import org.noear.solon.core.event.AppBeanLoadEndEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson2.JSON;
import com.googlecode.aviator.AviatorEvaluator;
import com.googlecode.aviator.Expression;
import com.openlogic.common.core.utils.DateUtils;
import com.openlogic.common.logic.constants.RuleConstants;
import com.openlogic.common.logic.node.enums.NodeExecEnums;
import com.openlogic.common.logic.node.factory.NodeExecFactory;
import com.openlogic.common.logic.utils.NumericRegxUtils;
import com.openlogic.common.logic.utils.StackExceptionUtils;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

/**
* @ClassName: ExecDefaultNodeHandler
* @Description: 默认节点运行执行器
* @author weiyongpeng
* @date 2024年7月17日 上午9:12:36
 */
@Component
public class ExecDefaultNodeHandler extends ExecRuleHandler{
	
	private static final Logger logger = LoggerFactory.getLogger(ExecDefaultNodeHandler.class);
	
	@Override
	public JSONObject typeRun(JSONArray resultArray1,JSONArray nodeArray,JSONArray lineArray,JSONObject inputjson,JSONArray areaArray,String areaFirst,String ruleId,StringBuffer reason,Map<String,Object> map) {
		JSONObject reJson = new JSONObject();
		logger.info("DefaultNode Begin Run Starting...");
		// 默认节点解析后的数据
		logger.info("typeRun=====" +  resultArray1.toString());
		reJson = recRunForNode(resultArray1,nodeArray,lineArray,inputjson,areaArray,areaFirst,ruleId,reason,map);	
		return reJson;
	}

	/**
	* 描述：迭代节点执行
	* @Title: recRunForNode
	* @param resultArray1
	* @param nodeArray
	* @param lineArray
	* @param inputjson
	* @param areaArray
	* @param areaFirst
	* @param ruleId
	* @param reason
	* @param map
	* @return
	* @author weiyongpeng
	* @date  2024年7月17日 上午10:29:23
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	@Override
	public JSONObject recRunForNode(JSONArray resultArray1, JSONArray nodeArray, JSONArray lineArray,
			JSONObject inputjson, JSONArray areaArray, String areaFirst, String ruleId, StringBuffer reason,
			Map<String, Object> map) {
		Map<Object,Object> inParam = new HashMap<>();
		Map<Object,Object> outParam = new HashMap<>();
	    for (Object ijo : inputjson.entrySet()){
	    	if(!((Map.Entry)ijo).getKey().toString().equals("everyNodeList") && !((Map.Entry)ijo).getKey().toString().equals("areaInfo") ) {
	    		inParam.put(((Map.Entry)ijo).getKey().toString().replaceAll("\"", ""), ((Map.Entry)ijo).getValue().toString().replaceAll("\"", ""));
	    	}
	    }
		// 开始执行时间
		Date startDate = DateUtils.getNowDate();
		String startExecuateTime = DateUtils.formatDate(startDate, DateUtils.YYYY_MM_DD_HH_MM_SS);
		boolean result=true;
		int index=0;
		// 异常信息
		String errorMsg = "";
		// 流程执行结束的json对象
		JSONObject reJson = new JSONObject();
		// 发生异常的时候返回的json对象
		JSONObject errorJson = new JSONObject();
		// 下一个可执行节点的json对象
		JSONObject nextResult = new JSONObject();
		try {
			//如果
			String ifString = ((JSONObject)resultArray1.get(3)).get("if").toString();
			ifString = StringEscapeUtils.unescapeXml(ifString);
			//那么
			String successString = ((JSONObject)resultArray1.get(3)).get("success").toString();
			successString = StringEscapeUtils.unescapeXml(successString);
			//否则
			String failedString = ((JSONObject)resultArray1.get(3)).get("failed").toString();	
			failedString = StringEscapeUtils.unescapeXml(failedString);
			if(map.isEmpty()) {
				map = ((Map<String, Object>)Optional.ofNullable(JSONObject.fromObject(resultArray1.get(8))).orElse(new JSONObject()));
			}
			Iterator<String> it = inputjson.keys(); 
			Map<String, Object> env = inputjson;
			String ifStringOld = ifString;
			
			// 判断是否存在sql参数
			if (ifString.contains("@")) { // sql参数
				// 假如SQL参数是前缀带@  @MIN_VALUE > MAX_VALUE 
				//遍历替换if中的变量
				while(it.hasNext()){
					// 获得key
					String key = it.next(); 
					if (ifString.contains("@" + key + "@")) {
						// 根据参数名称查询SQL参数
						selectRuleSqlParamRes(inputjson, key, env);
						ifString = ifString.replaceAll("\\@" + key + "\\@", key);
						ifStringOld = ifStringOld.replaceAll("\\@"+key+"\\@", map.get(key).toString());
					} else if(extractStrings(ifString).stream().filter(s -> s.split("\\.").length >= 2).collect(Collectors.toList()).size() > 0) {
						// @sqlVar2.NAME@.contains('10')
						List<String> sqlVarList = extractStrings(ifString).stream().filter(s -> s.split("\\.").length >= 2).collect(Collectors.toList());
						for (String sqlVar : sqlVarList) {
							String[] sqlSplit = sqlVar.split("\\.");
							// 取出需要对比的字段
							String compareVar = sqlSplit[1];
							List<Object> columnValueList = new ArrayList<>();
							if (sqlSplit[0].equals(key)) {
								List<Map<String,Object>> listObjectFir = (List<Map<String,Object>>) com.alibaba.fastjson.JSONArray.parse((String)sqlCache.get(key));
								if (CollectionUtils.isEmpty(listObjectFir)) {
									listObjectFir = selectRuleSqlParamRes(inputjson, key, env);
								}
								columnValueList = listObjectFir.stream().filter(mapF -> Optional.ofNullable(mapF.get(compareVar)).isPresent()).map(mapV -> {
									Object value = mapV.get(compareVar);
									return value;
								}).collect(Collectors.toList());
								env.put(sqlVar.replaceAll("\\.", ""), columnValueList);
								ifString = ifString.replaceAll("\\@"+sqlVar+"\\@", sqlVar.replaceAll("\\.", ""));
								ifStringOld = ifStringOld.replaceAll("\\@"+sqlVar+"\\@", map.get(key).toString());
							}else {
								break;
							}
						}
					} 
				}
			}
			ifStringOld = ifStringOld.replaceAll("&&", "并且").replaceAll("\\|\\|", "或者");
			//执行if判断
		    try {
		    	Expression compile = AviatorEvaluator.compile(ifString,true);
				result = (Boolean)compile.execute(env);
			} catch (Exception e) {
				errorMsg = StackExceptionUtils.getExceptionType(e).toString();
				logger.error("异常信息:{}",e.getMessage());
			}
		    //if执行结果
			if(result) {//执行name部分
				reason = reason.append("满足：").append(ifStringOld).append(",");
				String[] succlist =  successString.split("&@");
				for(int k=0,succlength=succlist.length;k<succlength;k++) {
					String[] succlist1 = succlist[k].split("=");
					for(int h=0,succlength1=succlist1.length;h<succlength1;h++) {
						if(h==0) {
							//遍历替换success中的变量
							inputjson = sortJson(inputjson);//排序避免替换错误
							
							//执行自定义函数
							if(succlist1[1].contains("(")||succlist1[1].contains("+")||succlist1[1].contains("-")||succlist1[1].contains("*")||succlist1[1].contains("/")) {
								String[] temp = succlist1[1].split("\\^");
								String tempStr = "";
								for(int i =0;i<temp.length;i++) {
									// 自定义函数
									if(temp[i].indexOf("com")!=-1) {
										tempStr+=temp[i];
									}else { // 普通计算
										Iterator<String> it1 = inputjson.keys(); 
										while(it1.hasNext()){
											// 获得key
											String key = it1.next(); 
											if(temp[i].replaceAll("\\@", "").split("\\.").length >= 2) {
												List<String> funcVars = Arrays.asList(temp[i].replaceAll("\\(", "").replaceAll("\\)", "").split("\\,"))
																			.stream()
																			.filter(x -> !NumericRegxUtils.isNumber(x))
																			.collect(Collectors.toList());
												for (String var : funcVars) {
													String[] sqlSplit = var.replaceAll("\\@", "").split("\\.");
													if(sqlSplit.length < 2) break;
													// 取出需要对比的字段
													String compareVar = sqlSplit[1];
													List<Map<String,String>> columnValueList = new ArrayList<>();
													if (sqlSplit[0].equals(key)) {
														List<Map<String,Object>> listObjectFir = (List<Map<String,Object>>) com.alibaba.fastjson.JSONArray.parse((String)sqlCache.get(key));
														if (CollectionUtils.isEmpty(listObjectFir)) {
															// 根据参数名称查询SQL参数
															listObjectFir = selectRuleSqlParamRes(inputjson, key, env);
														}
														columnValueList = listObjectFir.stream().filter(mapF -> Optional.ofNullable(mapF.get(compareVar)).isPresent()).map(mapV -> {
															Map<String,String> m = new HashMap<>();
															Object value = mapV.get(compareVar);
															m.put(compareVar, String.valueOf(value));
															return m;
														}).collect(Collectors.toList());
														temp[i] = temp[i].replaceAll(var, var.replaceAll("\\@", ""));
														env.put(var.replaceAll("\\@", ""), columnValueList);
														break;
													}
												}
											} else if(temp[i].contains("@" + key + "@")) {
												temp[i] = temp[i].replaceAll("\\@" + key + "\\@", key);
												List<Map<String,Object>> listObjectFir = Optional.ofNullable(sqlCache.get(key)).isPresent() ? (List<Map<String,Object>>) com.alibaba.fastjson.JSONArray.parse((String)sqlCache.get(key)) : selectRuleSqlParamRes(inputjson, key, env);
												env.put(key, listObjectFir);
												break;
											}
										}
										tempStr+=temp[i];
									}
								}
								try {
									Expression compile = AviatorEvaluator.compile(tempStr,true);
									Object res = compile.execute(env);
									
									//赋值
									inputjson.put(succlist1[0], res);
								} catch (Exception e) {
									errorMsg = StackExceptionUtils.getExceptionType(e).toString();
									logger.error("异常信息:{}",e.getMessage());
								}
							}else {
								Iterator<String> it1 = inputjson.keys(); 
								while(it1.hasNext()) {
									// 获得key
									String key = it1.next(); 
									if(succlist1[1].replaceAll("\\@", "").split("\\.").length >= 2) {
										String[] sqlSplit = succlist1[1].replaceAll("\\@", "").split("\\.");
										// 取出需要对比的字段
										String compareVar = sqlSplit[1];
										List<Object> columnValueList = new ArrayList<>();
										if (sqlSplit[0].equals(key)) {
											List<Map<String,Object>> listObjectFir = (List<Map<String,Object>>) com.alibaba.fastjson.JSONArray.parse((String)sqlCache.get(key));
											if (CollectionUtils.isEmpty(listObjectFir)) {
												listObjectFir = selectRuleSqlParamRes(inputjson, key, env);
											}
											columnValueList = listObjectFir.stream().filter(mapF -> Optional.ofNullable(mapF.get(compareVar)).isPresent()).map(mapV -> {
												Object value = mapV.get(compareVar);
												return value;
											}).collect(Collectors.toList());
											
											succlist1[1] = JSON.toJSONString(columnValueList);
										}
									}else {
										//特别注意数字不带单引号，字符串带单引号 SQL参数直接替换值
										//succlist1[1] = succlist1[1].contains("@" + key + "@") ? Optional.ofNullable(sqlCache.get(key)).isPresent() ? (String)sqlCache.get(key) : JSON.toJSONString(selectRuleSqlParamRes(inputjson, key, env)) : succlist1[1].replaceAll(key, NumericRegxUtils.isNumber(inputjson.getString(key))?inputjson.getString(key):"'"+inputjson.getString(key)+"'");
										succlist1[1] = succlist1[1].contains("@" + key + "@") ? Optional.ofNullable(sqlCache.get(key)).isPresent() ? (String)sqlCache.get(key) : JSON.toJSONString(selectRuleSqlParamRes(inputjson, key, env)) : succlist1[1].replaceAll(key,inputjson.getString(key));
									}
								}
								//赋值
								inputjson.put(succlist1[0], succlist1[1]);
							}
						}
					}
				}
			}else {//执行否则部分
				reason = reason.append("不满足：").append(ifStringOld).append(",");
				index=-1;
				String[] failedlist =  failedString.split("&@");
				for(int k=0,failedlength=failedlist.length;k<failedlength;k++) {
					String[] failedlist1 = failedlist[k].split("=");
					for(int h=0,failedlength1=failedlist1.length;h<failedlength1;h++) {
						if(h==0) {
							//遍历替换success中的变量
							inputjson = sortJson(inputjson);
							
							//执行自定义函数
							if(failedlist1[1].contains("(")||failedlist1[1].contains("+")||failedlist1[1].contains("-")||failedlist1[1].contains("*")||failedlist1[1].contains("/")) {
								String[] temp = failedlist1[1].split("\\^");
								String tempStr = "";
								for(int i =0;i<temp.length;i++) {
									if(temp[i].indexOf("com")!=-1) {
										tempStr+=temp[i];
									}else {
										Iterator<String> it1 = inputjson.keys(); 
										while(it1.hasNext()){
											// 获得key
											String key = it1.next(); 
											if(temp[i].replaceAll("\\@", "").split("\\.").length >= 2) {
												List<String> funcVars = Arrays.asList(temp[i].replaceAll("\\(", "").replaceAll("\\)", "").split("\\,"))
																			.stream()
																			.filter(x -> !NumericRegxUtils.isNumber(x))
																			.collect(Collectors.toList());
												for (String var : funcVars) {
													String[] sqlSplit = var.replaceAll("\\@", "").split("\\.");
													if(sqlSplit.length < 2) break;
													// 取出需要对比的字段
													String compareVar = sqlSplit[1];
													List<Map<String,String>> columnValueList = new ArrayList<>();
													if (sqlSplit[0].equals(key)) {
														List<Map<String,Object>> listObjectFir = (List<Map<String,Object>>) com.alibaba.fastjson.JSONArray.parse((String)sqlCache.get(key));
														if (CollectionUtils.isEmpty(listObjectFir)) {
															// 根据参数名称查询SQL参数
															listObjectFir = selectRuleSqlParamRes(inputjson, key, env);
														}
														columnValueList = listObjectFir.stream().filter(mapF -> Optional.ofNullable(mapF.get(compareVar)).isPresent()).map(mapV -> {
															Map<String,String> m = new HashMap<>();
															Object value = mapV.get(compareVar);
															m.put(compareVar, String.valueOf(value));
															return m;
														}).collect(Collectors.toList());
														temp[i] = temp[i].replaceAll(var, var.replaceAll("\\@", ""));
														env.put(var.replaceAll("\\@", ""),columnValueList);
														break;
													}
												}
											} else if(temp[i].contains("@" + key + "@")) {
												temp[i] = temp[i].replaceAll("\\@" + key + "\\@", key);
												List<Map<String,Object>> listObjectFir = Optional.ofNullable(sqlCache.get(key)).isPresent() ? (List<Map<String,Object>>) com.alibaba.fastjson.JSONArray.parse((String)sqlCache.get(key)) : selectRuleSqlParamRes(inputjson, key, env);
												env.put(key, listObjectFir);
												break;
											}
										}
										tempStr+=temp[i];
									}
								}
								try {
									// logger.info("执行否则部分 tempStr={}", tempStr);
									Expression compile = AviatorEvaluator.compile(tempStr,true);
									Object res = compile.execute(env);
									
									//赋值
									inputjson.put(failedlist1[0], res);
								} catch (Exception e) {
									errorMsg = StackExceptionUtils.getExceptionType(e).toString();
									logger.error("异常信息:{}",e.getMessage());
								}
							}else {
								Iterator<String> it1 = inputjson.keys(); 
								while(it1.hasNext()){
									// 获得key
									String key = it1.next(); 
									if(failedlist1[1].replaceAll("\\@", "").split("\\.").length >= 2) {
										String[] sqlSplit = failedlist1[1].replaceAll("\\@", "").split("\\.");
										// 取出需要对比的字段
										String compareVar = sqlSplit[1];
										List<Object> columnValueList = new ArrayList<>();
										if (sqlSplit[0].equals(key)) {
											List<Map<String,Object>> listObjectFir = (List<Map<String,Object>>) com.alibaba.fastjson.JSONArray.parse((String)sqlCache.get(key));
											if (CollectionUtils.isEmpty(listObjectFir)) {
												listObjectFir = selectRuleSqlParamRes(inputjson, key, env);
											}
											columnValueList = listObjectFir.stream().filter(mapF -> Optional.ofNullable(mapF.get(compareVar)).isPresent()).map(mapV -> {
												Object value = mapV.get(compareVar);
												return value;
											}).collect(Collectors.toList());
											
											failedlist1[1] = JSON.toJSONString(columnValueList);
										}
									}else {
										//特别注意数字不带单引号，字符串带单引号 SQL参数直接替换值
										// failedlist1[1] = failedlist1[1].contains("@" + key + "@") ? Optional.ofNullable(sqlCache.get(key)).isPresent() ? (String)sqlCache.get(key) : JSON.toJSONString(selectRuleSqlParamRes(inputjson, key, env)) : failedlist1[1].replaceAll(key, NumericRegxUtils.isNumber(inputjson.getString(key))?inputjson.getString(key):"'"+inputjson.getString(key)+"'");
										failedlist1[1] = failedlist1[1].contains("@" + key + "@") ? Optional.ofNullable(sqlCache.get(key)).isPresent() ? (String)sqlCache.get(key) : JSON.toJSONString(selectRuleSqlParamRes(inputjson, key, env)) : failedlist1[1].replaceAll(key,inputjson.getString(key));
									}
								}
								//赋值
								inputjson.put(failedlist1[0], failedlist1[1]);
							}
						}
					}
				}
			}
		} catch (Exception e) {
			errorMsg = StackExceptionUtils.getExceptionType(e).toString();
			logger.error("默认节点执行异常,异常信息:{}",e.getMessage());
		}
		
		if (errorMsg == null || errorMsg.equals("")) {
			for (Object ijo : inputjson.entrySet()){
		    	if(!((Map.Entry)ijo).getKey().toString().equals("everyNodeList") && !((Map.Entry)ijo).getKey().toString().equals("areaInfo") ) {
		    		outParam.put(((Map.Entry)ijo).getKey().toString().replaceAll("\"", ""), ((Map.Entry)ijo).getValue().toString().replaceAll("\"", ""));
		    	}
		    }

			reJson = inputjson;
			if(resultArray1.get(2).equals("area")) {
				if(areaFirst.equals("")) {//判断是否是循环的第一个 节点
					areaFirst = resultArray1.getString(0);
					reJson.put("areaFirst", areaFirst);
				}
			}
			nextResult = runNextNode(resultArray1,nodeArray,lineArray,inputjson,areaArray,areaFirst,ruleId,index,reason,map,startDate,inParam,outParam);
			if(!nextResult.toString().equals("{}")) {
				return nextResult;
			}
		}else {
			Map<Object,Object> errorMap = new HashMap<>();
			errorMap.put("msg", errorMsg);
			errorJson = JSONObject.fromObject(errorMap);
			// 执行异常信息
			nextResult = runNextNodeThrow(resultArray1,nodeArray,lineArray,inputjson,areaArray,areaFirst,ruleId,index,reason,map,startDate,inParam,errorJson);
			if(!nextResult.toString().equals("{}")) {
				return nextResult;
			}
		}
		// 结束执行时间
		Date endDate = DateUtils.getNowDate();
		String endExecuateTime = DateUtils.formatDate(endDate, DateUtils.YYYY_MM_DD_HH_MM_SS);
		reJson.put("startExecTime", startExecuateTime);
		reJson.put("endExecTime", endExecuateTime);
		reJson.put("inParam", ",入参为:【" + inParam + "】");
		reJson.put("outParam", ",执行结果为:【" + outParam + "】");
		reJson.put("execTotalTimeMills", "耗时: " + (endDate.getTime() - startDate.getTime()) + " 毫秒");
		reJson.put("execStatus", RuleConstants.NODE_EXEC_SUCCESS);
		return reJson;
	}

	public JSONObject getAreaInfoList(JSONObject inputjson,String nodeId) {
		JSONObject AreaInfo = new JSONObject();
		JSONArray AreaInfoList = new JSONArray();
		JSONArray everyNodeList = new JSONArray();
		if(inputjson.get("areaInfo")!=null) {
			AreaInfo= (JSONObject) inputjson.get("areaInfo");
			AreaInfoList = (JSONArray) AreaInfo.get(nodeId);
			if(AreaInfoList==null) {
				AreaInfoList = new JSONArray();
			}
		}
		if(inputjson.get("everyNodeList")!=null) {
			everyNodeList= (JSONArray) inputjson.get("everyNodeList");
		}
		inputjson.remove("areaInfo");
		inputjson.remove("areaFirst");
		inputjson.remove("everyNodeList");
		AreaInfoList.add(inputjson);
		AreaInfo.put(nodeId, AreaInfoList);
		inputjson.put("areaInfo", AreaInfo);
		inputjson.put("everyNodeList", everyNodeList);
		return inputjson;
	}

	@Override
	public void onEvent(AppBeanLoadEndEvent event) throws Throwable {
		NodeExecFactory.register(NodeExecEnums.DEFAULT_NODE.getCode(), this);
	}

}
